package com.kedacom.freedomLabel.model.db;

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.kedacom.freedomLabel.AppExecutors;
import com.kedacom.freedomLabel.model.db.dao.IDao;
import com.kedacom.freedomLabel.utils.log.LLog;

import java.util.ArrayList;
import java.util.List;

/**
 * @author licheng
 * @since 2019/11/15 14:50
 */
public class DataLoader {

    private static final String TAG = DataLoader.class.getSimpleName();

    private static AppExecutors sExecutors;
    private static Handler sHandler = new Handler();
    private static Gson sGson = new GsonBuilder()
            .serializeNulls()
            .create();

    static {
        sExecutors = AppExecutors.getInstance();
    }

    public static void count(@NonNull final IDao dao, final DataCallback<Integer> callback) {
        sExecutors.queryIO().execute(() -> {
            try {
                int count = dao.count();
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :COUNT data success");
                postSuccess(callback, count);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :COUNT data failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> void get(@NonNull final IDao<T> dao, final @NonNull String param, final DataCallback<List<T>> callback) {
        sExecutors.queryIO().execute(() -> {
            try {
                List<T> data = dao.get(param);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param + "] success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param + "] failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }



    public static <T> void get(@NonNull final IDao<T> dao, final @NonNull String param1, @NonNull String param2,
                               final DataCallback<List<T>> callback) {
        sExecutors.queryIO().execute(() -> {
            try {
                List<T> data = dao.get(param1, param2);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param1 + "," + param2 + "] success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param1 + "," + param2 + "] failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    private static <T> void postSuccess(final DataCallback<T> callback, final T data) {
        sHandler.post(() -> {
            callback.success(data);
            LLog.debug(TAG, sGson.toJson(data));
        });
    }

    private static <T> void postError(final DataCallback<T> callback, final String error) {
        sHandler.post(() -> callback.error(error));
    }

    public static <T> LiveData<List<T>> get(@NonNull final IDao<T> dao) {
        final MutableLiveData<List<T>> liveData = new MutableLiveData<>();
        sExecutors.queryIO().execute(() -> {
            try {
                List<T> data = dao.get();
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :GET data success");
                LLog.debug(TAG, sGson.toJson(data));
                liveData.postValue(data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :GET data failed " + e.getMessage());
                liveData.postValue(null);
            }
        });
        return liveData;
    }

    public static <T> void get(@NonNull final IDao<T> dao, final DataCallback<List<T>> callback) {
        sExecutors.queryIO().execute(() -> {
            try {
                List<T> data = dao.get();
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :GET data success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :GET data failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> void update(@NonNull final IDao<T> dao, final @NonNull T data) {
        update(dao, data, null);
    }

    public static <T> void update(@NonNull final IDao<T> dao, final @NonNull T data, final @Nullable DataCallback<T> callback) {
        sExecutors.insertIO().execute(() -> {
            dao.update(data);
            LLog.debug(TAG, dao.getClass().getSimpleName() + " :UPDATE data success");
            LLog.debug(TAG, sGson.toJson(data));
            if (callback != null) {
                postSuccess(callback, data);
            }
        });
    }

    public static <T> void save(@NonNull final IDao<T> dao, final @NonNull T data) {
        sExecutors.insertIO().execute(() -> {
            dao.save(data);
            LLog.debug(TAG, dao.getClass().getSimpleName() + " :SAVE data success");
            LLog.debug(TAG, sGson.toJson(data));
        });
    }

    public static <T> void save(@NonNull final IDao<T> dao, final @NonNull List<T> data) {
        sExecutors.insertIO().execute(() -> {
            dao.save(data);
            LLog.debug(TAG, dao.getClass().getSimpleName() + " :SAVE data success");
            LLog.debug(TAG, sGson.toJson(data));
        });
    }

    public static <T> void save(@NonNull final IDao<T> dao, final @NonNull T data, final @NonNull DataCallback<T> callback) {
        sExecutors.insertIO().execute(() -> {
            try {
                dao.save(data);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :SAVE data success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :SAVE data failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> void save(@NonNull final IDao<T> dao, final @NonNull List<T> data, final @NonNull DataCallback<List<T>> callback) {
        sExecutors.insertIO().execute(() -> {
            try {
                dao.save(data);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :SAVE data success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :SAVE data failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> void delete(@NonNull final IDao<T> dao, final @NonNull T data, final @NonNull DataCallback<T> callback) {
        sExecutors.insertIO().execute(() -> {
            try {
                dao.delete(data);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :DELETE data success");
                postSuccess(callback, data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :DELETE data failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> void delete(@NonNull final IDao<T> dao, final @Nullable String param, final @NonNull DataCallback<T> callback) {
        sExecutors.insertIO().execute(() -> {
            try {
                if (TextUtils.isEmpty(param)) {
                    dao.delete();
                } else {
                    dao.delete(param);
                }
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :DELETE data with param [" + param + "] success");
                postSuccess(callback, null);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :DELETE data with param [" + param + "] failed " + e.getMessage());
                postError(callback, e.getMessage());
            }
        });
    }

    public static <T> LiveData<List<T>> get(@NonNull final IDao<T> dao, final @NonNull String param) {
        final MutableLiveData<List<T>> liveData = new MutableLiveData<>();
        sExecutors.queryIO().execute(() -> {
            try {
                List<T> data = dao.get(param);
                LLog.debug(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param + "] success");
                LLog.debug(TAG, sGson.toJson(data));
                liveData.postValue(data);
            } catch (Exception e) {
                LLog.error(TAG, dao.getClass().getSimpleName() + " :GET data with param [" + param + "] failed " + e.getMessage());
                liveData.postValue(null);
            }
        });
        return liveData;
    }



}